{
   "metadata":{
      "orig_nbformat":4,
      "kernelspec":{
         "name":"Lua",
         "display_name":"Lua",
         "language":"lua"
      },
      "language_info":{
         "file_extension":".lua",
         "mimetype":"text/x-luasrc",
         "name":"lua",
         "version":"14.0.0"
      }
   },
   "nbformat_minor":5,
   "nbformat":4,
   "cells":[
      {
         "cell_type":"code",
         "source":"math = require(\"math\")\n\n-- the game of life class itself\nGameOfLife = {}\nGameOfLife.__index = GameOfLife\nfunction GameOfLife:Create(grid_size)\n    local this =\n    {\n        grid_size = grid_size or {10,10},\n        grid = {}\n    }\n    setmetatable(this, GameOfLife)\n    this.size = this.grid_size[1] * this.grid_size[2]\n    for i=1,this.size do\n        this.grid[i] = 0\n    end\n    return this\nend",
         "metadata":{
            "trusted":true
         },
         "execution_count":null,
         "outputs":[
            
         ],
         "id":"61dc1d13-5546-477d-a162-e18ec564e3ee"
      },
      {
         "cell_type":"code",
         "source":"-- member function to initalize with some random values\nfunction GameOfLife:init_random(p)\n    for i=1,self.size do\n        self.grid[i] = (math.random() < p) and 1 or 0\n    end\nend",
         "metadata":{
            "trusted":true
         },
         "execution_count":null,
         "outputs":[
            
         ],
         "id":"72da5a15-dd9d-4a62-bfa3-5a3ec457c5f4"
      },
      {
         "cell_type":"code",
         "source":"-- helper function to convert a coordinate {x,y} into a \n-- scalar offset\nfunction GameOfLife:to_offset(coord)\n    return (coord[1]-1) * self.grid_size[2] + (coord[2] -1) + 1\nend\n-- helper function to access the value of the grid at a coordinate {x,y}\nfunction GameOfLife:at(coord)\n    return self.grid[self:to_offset(coord)]\nend",
         "metadata":{
            "trusted":true
         },
         "execution_count":null,
         "outputs":[
            
         ],
         "id":"0b341677-64f2-4ef3-8ea4-a8e2eb275df2"
      },
      {
         "cell_type":"code",
         "source":"-- the function to do a step\nfunction GameOfLife:step()\n    new_grid = {}\n  \n    for x=1,self.grid_size[1] do\n        for y=1, self.grid_size[2] do\n            \n            local c = 0\n            for xx=-1,1 do\n                for yy=-1,1 do\n                    nx = x + xx\n                    ny = y + yy\n                    if nx >=1 and ny>=1 and nx <=self.grid_size[1] and ny <=self.grid_size[2] and not (xx==0 and yy ==0) then\n                        c = c + self:at({nx,ny})\n                    end\n                end\n            end\n            \n            local offset =  self:to_offset({x,y})\n            local current_state = self:at({x,y})\n            \n            new_grid[offset] = 0\n            if current_state == 0 then\n                if c == 3 then\n                    new_grid[offset] = 1\n                end\n            else\n                if c==2 or c==3 then\n                    new_grid[offset] = 1\n                else\n                    new_grid[offset] = 0\n                end\n            end\n--             \n        end\n    end\n    self.grid = new_grid\nend",
         "metadata":{
            "trusted":true
         },
         "execution_count":null,
         "outputs":[
            
         ],
         "id":"7958dd53-006c-480d-a4ad-9f04b147fd29"
      },
      {
         "cell_type":"code",
         "source":"-- helper function to draw the grid as string\nfunction GameOfLife:__tostring()\n    s = \"*\"\n    for y=1, self.grid_size[2] do\n        s = s .. \"--\"\n    end\n    s =  s .. \"*\\n\"\n    for x=1,self.grid_size[1] do\n        s = s .. \"|\"\n        for y=1, self.grid_size[2] do\n            local state = self:at({x,y})\n            if state == 0 then\n                ss = \" \"\n            else\n                ss =  \"O\"\n            end\n            s = s .. ss .. \" \"\n        end\n        s =  s .. \"|\\n\"\n    end\n     s =  s .. \"*\"\n    for y=1, self.grid_size[2] do\n        s = s .. \"--\"\n    end\n    s =  s .. \"*\\n\"\n    return s\nend",
         "metadata":{
            "trusted":true
         },
         "execution_count":null,
         "outputs":[
            
         ],
         "id":"884414f6-8bc9-4719-9671-ef3be310356b"
      },
      {
         "cell_type":"code",
         "source":"-- initalize the game of life\ngrid_size = {20,20}\ngame_of_life = GameOfLife:Create(grid_size)\ngame_of_life:init_random(0.5)\n\n-- a tiny gui\nfunction speed_to_interval(speed)\n    return 1.0 / speed\nend\n\nspeed = 0.001\n\nhbox = ilua.widgets.hbox()\n\nplay = ilua.widgets.play({interval=speed_to_interval(speed), max=1000000})\noutput = ilua.widgets.output()\nstep_label = ilua.widgets.label({value=\"Step: \"..tostring(play.value)})\nspeed_label = ilua.widgets.label({value=\"Speed: \"..tostring(speed)})\nspeed_slider = ilua.widgets.slider({min=0.001, max=0.5, step=0.01})\n\nhbox:add(play,step_label,speed_label)\n\nspeed_slider:register_observer(function(value)\n    output:captured(function()\n    speed = value\n    play.interval = speed_to_interval(speed)\n    speed_label.value = \"Speed: \" .. tostring(speed)\n    end)\nend)\n\nplay:register_observer(function(value)\n    if value <= 0.1 then\n        game_of_life:init_random(0.24)\n    end\n    --  use output widget to caputre prints   \n    output:captured(function()\n        ilua.display.clear_output(false)\n        step_label.value = \"STEP \"..tostring(play.value)\n        game_of_life:step()\n        print(tostring(game_of_life))\n    end)\nend)\nilua.display.display(hbox,speed_slider, output)",
         "metadata":{
            "trusted":true
         },
         "execution_count":null,
         "outputs":[
            
         ],
         "id":"40cabf23-7eef-4501-badd-99c1a68c5ced"
      }
   ]
}